use std::fmt;

use from_pest::FromPest;
use pest::iterators;
use tracing::{debug, trace};

use crate::ast_define::{MetaInfo, Rule, get_meta_info};

#[derive(Debug, PartialEq)]
pub struct Ident {
    pub value: String,
    pub meta_info: MetaInfo,
}

impl Ident {
    pub fn new(value: String, meta_info: MetaInfo) -> Self {
        Self { value, meta_info }
    }
}

impl<'pest> FromPest<'pest> for Ident {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 Ident");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in Ident:\n{pair:#?}");
        let Rule::Ident = pair.as_rule() else {
            trace!("\npair.as_rule() {:#?} != Rule::Ident", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };
        let ident = pair.as_str().to_string();
        let meta_info = get_meta_info(pair.as_span());
        Ok(Ident::new(ident, meta_info))
    }
}
impl fmt::Display for Ident {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.value)
    }
}

#[derive(Debug, PartialEq)]
pub enum Number {
    HEX_INT(HEX_INT),
    OCT_INT(OCT_INT),
    DEC_INT(DEC_INT),
}

impl<'pest> FromPest<'pest> for Number {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 Number");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in Number:\n{pair:#?}");
        let Rule::Number = pair.as_rule() else {
            trace!("\n{:#?} != Rule::Number", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let mut inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::HEX_INT => Ok(Number::HEX_INT(HEX_INT::from_pest(&mut inner)?)),
            Rule::OCT_INT => Ok(Number::OCT_INT(OCT_INT::from_pest(&mut inner)?)),
            Rule::DEC_INT => Ok(Number::DEC_INT(DEC_INT::from_pest(&mut inner)?)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

impl fmt::Display for Number {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let format_num = match self {
            Number::HEX_INT(this) => this.0.to_string(),
            Number::OCT_INT(this) => this.0.to_string(),
            Number::DEC_INT(this) => this.0.to_string(),
        };
        write!(f, "{format_num}")
    }
}

#[derive(Debug, PartialEq)]
pub struct HEX_INT(String);

impl<'pest> FromPest<'pest> for HEX_INT {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 HEX_INT");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in HEX_INT:\n{pair:#?}");
        let Rule::HEX_INT = pair.as_rule() else {
            trace!("\npair.as_rule() {:#?} != Rule::HEX_INT", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };
        Ok(HEX_INT(pair.as_str().to_string()))
    }
}

#[derive(Debug, PartialEq)]
pub struct OCT_INT(String);

impl<'pest> FromPest<'pest> for OCT_INT {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 OCT_INT");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in OCT_INT:\n{pair:#?}");
        let Rule::OCT_INT = pair.as_rule() else {
            trace!("\npair.as_rule() {:#?} != Rule::OCT_INT", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };
        Ok(OCT_INT(pair.as_str().to_string()))
    }
}

#[derive(Debug, PartialEq)]
pub struct DEC_INT(String);

impl<'pest> FromPest<'pest> for DEC_INT {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 DEC_INT");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in DEC_INT:\n{pair:#?}");
        let Rule::DEC_INT = pair.as_rule() else {
            trace!("\npair.as_rule() {:#?} != Rule::DEC_INT", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };
        Ok(DEC_INT(pair.as_str().to_string()))
    }
}
